#include <cmath>
#include "ADataSet.hpp"
#include "global.hpp"

bool	_DEBUG = true;

const std::list<Data*>&		ADataSet::getSeq(unsigned int id) const
{
	return this -> _dataSets.find(id) -> second;
}

void				ADataSet::addData(Data* new_data)
{
	if (this -> _tmpList == NULL)
		this -> _tmpList = new std::list<Data*>;
	this -> _tmpList -> push_back(new_data);
}

void				ADataSet::nextData()
{
	this -> _dataSets.insert(std::pair<unsigned int, std::list<Data*> >(this->_dataSets.size(), *this->_tmpList));
	delete this -> _tmpList;
	this -> _tmpList = 0;
}

const std::map<unsigned int, double>&		ADataSet::getEntropies(DataManager* man)
{
	std::map<unsigned int, std::map<unsigned int, unsigned int> >	tmp_counts;
	std::map<unsigned int, std::list<Data*> >::iterator		it = this -> _dataSets.begin();
	std::map<unsigned int, std::list<Data*> >::iterator		ite = this -> _dataSets.end();
	std::list<Data*>::iterator					sit;
	std::list<Data*>::iterator					site;
	double								n_sets = static_cast<double>(this -> _dataSets.size());
	unsigned int							types_count = man -> getTypesCount();
	
	// Parcours des sequences de données pour compter le nombre d'occurences de chaque valeur

	for (; it != ite; ++it)
	{
		sit = it -> second.begin();
		site = it -> second.end();
		for (; sit != site; ++sit)
		{
			++tmp_counts[(*sit) -> getType()][(*sit) -> getValue()];
			if (G::lobal() -> debug())
			{
				std::cout << "Discovered element of type " << (*sit) -> getType() << " and value " << (*sit) -> getValue() << " which leads to a total of ";
				std::cout << tmp_counts[(*sit) -> getType()][(*sit) -> getValue()] << std::endl;
			}
		}
	}

	// Parcoure le tableau par type, par valeur
	// pour calculer l'entropie, la probabilité tmp_frac = nb d'occurences / nb de sequences de données
	
	unsigned int							values_count;
	double								tmp_frac;

	for (unsigned int i = 0; i < types_count; ++i)
	{
		values_count = man -> getType(i) -> getValuesCount();
		this -> _entropies[i] = 0;

		for (unsigned int j = 0; j < values_count; ++j)
		{
			tmp_frac = tmp_counts[i][j] / n_sets;
			if (tmp_frac != 0)
				this -> _entropies[i] -= tmp_frac * log2(tmp_frac);
			if (G::lobal() -> debug())
			{
				std::cout << "We have " << tmp_counts[i][j] << " times the value " << j << " of type " << i << " for a total of " << n_sets << " sequences, or ";
				std::cout << tmp_frac << " as probability. (new e(" << i << ") = " << this -> _entropies[i] << ")" << std::endl;
			}
		}
	}
	return this -> _entropies;
}


ADataSet::ADataSet() : _tmpList(0)
{

}
